//Project 3 - CS 3451 - Labyrinth Lite
//Instructor: Jarek Rossignac
//Author: Tyler Powell
//Date: September 2011

import processing.opengl.PGraphicsOpenGL;

final int FPS = 30; //frame rate
float time = 0; //current point in time
float time2 = 0; //next point in time to check collision with
float mouseTime = 0; //point in time the mouse last moved
pt ballAtMouseMove; //point of ball at last move
vec velAtMouseMove; //velocity of ball at last move
float angleOfRotationX = 0; //how much to rotate the screen by in the x direction
float angleOfRotationY = 0; //how much to rotate the screen by in the y direction
pt defaultBallLoc = new pt(-width,-height); //the initial point of the ball
int DEFAULTCOUNTDOWN = 500; //base countDown
int countDown = DEFAULTCOUNTDOWN; //timer that counts down to zero

void setup() { //initial setup, runs once
  size(800,600,OPENGL);
  sphereDetail(12);
  frameRate(FPS);
  setupFace();
  textFont(createFont("verdana",12));
}

void draw () { //draw shapes
  background(255);
  countDown--;
  if(info){ //display ui info
    drawInfo();
    drawFace();
  }
  if(!edit){ //if not in edit mode, draw the timer bar
      fill(color(0,0,255));
      rect(110,35,(width-240)*countDown/DEFAULTCOUNTDOWN,10);
      noFill();
      stroke(0);
      rect(110,35,(width-240),10);
      noStroke();
  } else { //set the timer to keep it from running out while editing
    countDown = DEFAULTCOUNTDOWN;
  }
  if(gameWon){ //when gate reached display win screen
    pushMatrix();
    fill(color(0,255,0));
    rect(0,0,width,height);
    fill(color(255,0,255));
    textFont(createFont("verdana",36));
    text("YOU WIN!",width/2-80,height/2);
    noFill();
    popMatrix();
  }
  else if(countDown>0){ //while game is still in progress, draw the models
    pushMatrix();
    if(threeD){
      directionalLight(250, 250, 250, 20, 100, -100);
      angleOfRotationX = -(mouseY-height/2.0)/height*PI/2;
      angleOfRotationY = (mouseX-width/2.0)/width*PI/2;
      translate(width/2,height/2,0); //move to center of screen to allow for rotation about center
  //    rotateX(ang);
      //rotateY(ang);
  //    fill(150);
  //    text("hello world", 0,0);
  //    noFill();
  //    rotateY(PI/4);
    }
    
    
    
    
    
    drawWalls(threeD);
    drawBall(threeD);
    if(!edit){ //detect collisions
      time += .0001;
      time2 = time + .0001;
//      float maxVel = 5;
//      if(currentVelocity.norm()>maxVel){ //limit the max velocity
//        currentVelocity.scaleBy(maxVel/currentVelocity.norm());
//      }
//      float minVel = 200;
//      if(currentVelocity.norm()<minVel){
//        println(currentVelocity.scaleBy(minVel/currentVelocity.norm()).norm());
//      }
      pt loc1 = location(time, currentVelocity, ballLocation);
      pt loc2 = location(time2, velocity(time2,currentVelocity),loc1);
      if(!collision(loc1,loc2)){
        updateVelocity(time, currentVelocity);
        loc1 = location(time, currentVelocity, ballLocation);
        placeBall(loc1);
      }
//      placeBall(loc1);
    } else {
      DEFAULTCOUNTDOWN = 500 + 100*labPoints.size(); //calculate the time for the play based on how many points have been placed
      time = 0;
    }
    popMatrix();
  } else if(!gameWon) { //draw the losing screen since time has run out
    pushMatrix();
    fill(color(255,0,0));
    rect(0,0,width,height);
    fill(color(0,255,255));
    textFont(createFont("verdana",36));
    text("YOU LOSE!",width/2-80,height/2);
    noFill();
    popMatrix();
  }
}

void mousePressed() {
  if(mouseButton == LEFT && edit) { //left click in edit mode adds points
    addPoint(mouseX,mouseY,align);
  }
  if(mouseButton == RIGHT && edit) { //right click in edit mode places ball
    currentVelocity = new vec(0,0);
    defaultBallLoc = new pt(mouseX,mouseY);
    placeBall(mouseX,mouseY);
  }
}

void mouseDragged() {
  
}

void mouseMoved() { //when mouse moves, update these variables
  mouseTime=time;
  ballAtMouseMove = ballLocation;
  velAtMouseMove = currentVelocity;
}

void mouseReleased() {
  
}

void keyPressed() {
  if(key=='3') {
    threeD = !threeD; 
  }
  if(key=='d') { //toggle Debug Mode
    debugMode = !debugMode;
  }
  if(key==BACKSPACE && edit) { //delete last point
    if(!labPoints.isEmpty()) { //check to keep index in bounds
      labPoints.remove(labPoints.size()-1);
    }
    if(!walls.isEmpty()) {
      walls.remove(walls.size()-1);
    }
  }
  if(key==DELETE && edit) { //delete all points
    if(!labPoints.isEmpty()){ //no reason to make the garbage collector work harder
      labPoints = new ArrayList<pt>();
      placeBall(-width,-height);
    }
    if(!walls.isEmpty()) {
      walls = new ArrayList<vec>();
    }
  } 
  if(keyCode==SHIFT) { //align lines with x or y axis, key must be held
    align = true;
  }
  if(key=='e') { //toggle edit mode
    edit = true;
    countDown = DEFAULTCOUNTDOWN;
    textFont(createFont("verdana",12));

  }
  if(keyCode==UP) {
    if(edit){
      incrementBallSize();
    }
  }
  if(keyCode==DOWN) {
    if(edit){
      decrementBallSize();
    }
  }
  if(keyCode==LEFT){
    gravitationalConstant-=.1;
    if(gravitationalConstant < 0){
      gravitationalConstant = 2;
    }
  }
  if(keyCode==RIGHT){
    gravitationalConstant+=.1;
    if(gravitationalConstant > 2){
      gravitationalConstant = 0;
    }
  }
  
  if(key=='s') {
    saveData();
  }
  if(key=='l') {
    loadData();
    defaultBallLoc = ballLocation;
  }
  if(key==' ') { //start/restart a game
    edit = false;
    ballLocation = defaultBallLoc;
    countDown = DEFAULTCOUNTDOWN;
    time = 0;
    currentVelocity = new vec(0,0);
    textFont(createFont("verdana",12));
    gameWon = false;
  }
  if(key=='h') { //remove UI
    info = !info;
  }
  if(key=='p') {
    takePicture();
  }
}

void keyReleased() {
  if(keyCode==SHIFT) {
    align = false;
  }
}


